package handler

import (
	"context"
	"encoding/json"
	"github.com/gin-gonic/gin"
	jwt "github.com/golangblogs/gojwt"
	"github.com/gorilla/websocket"
	"log"
	"math/rand"
	"net/http"
	"soul/api/request"
	"soul/dao"
	"soul/initiate"
	"soul/pkg"
	"strconv"
	"time"
)

func SendSms(c *gin.Context) {
	var data request.Send
	err := c.ShouldBind(&data)
	if err != nil {
		c.JSON(http.StatusOK, gin.H{
			"code": 1000,
			"msg":  err.Error(),
			"data": nil,
		})
		return
	}
	code := rand.Intn(9000) + 1000
	_, err = pkg.SendSms(data.Phone, strconv.Itoa(code))
	if err != nil {
		c.JSON(http.StatusOK, gin.H{
			"code": 1000,
			"msg":  err.Error(),
			"data": nil,
		})
		return
	}
	initiate.Client.Set(context.Background(), "sendsms"+data.Source+data.Phone, code, time.Minute*30)
	c.JSON(http.StatusOK, gin.H{
		"code": 200,
		"msg":  "成功",
		"data": nil,
	})
}

func Login(c *gin.Context) {
	var data request.Login
	err := c.ShouldBind(&data)
	if err != nil {
		c.JSON(http.StatusOK, gin.H{
			"code": 1000,
			"msg":  err.Error(),
			"data": nil,
		})
		return
	}
	user := dao.LoginUserByPhone(data.Phone, data.Password, data.Code)
	if user.ID == 0 {
		dao.CreateUserByPhone(data.Phone, data.Password)
		c.JSON(http.StatusOK, gin.H{
			"code": 200,
			"msg":  "创建成功",
			"data": user,
		})
		return
	} else {
		dao.LoginUserByPhone(data.Phone, data.Password, data.Code)
	}
	claim := jwt.CustomClaims{
		ID: user.ID,
	}
	token, err := jwt.NewJWT("2209a").CreateToken(claim)
	if err != nil {
		c.JSON(http.StatusOK, gin.H{
			"code": 1000,
			"msg":  "token解析失败",
			"data": nil,
		})
	}
	c.JSON(http.StatusOK, gin.H{
		"code": 200,
		"msg":  "登录成功",
		"data": token,
	})
}

func Upload(c *gin.Context) {
	file, err := c.FormFile("file")
	if err != nil {
		c.JSON(http.StatusOK, gin.H{
			"code": 1000,
			"msg":  err,
			"data": nil,
		})
		return
	}
	ext := file.Filename
	if ext != ".txt" && ext != ".mp4" && ext != ".png" && ext != ".jpg" {
		c.JSON(http.StatusOK, gin.H{
			"code": 1000,
			"msg":  "文件格式不正确",
			"data": nil,
		})
	}
	log.Println(file.Filename)

	dst := "/D:\\GoWork\\zg3\\rk\\monthly\\soul\\image\\img\\" + file.Filename
	// 上传文件至指定的完整文件路径
	c.SaveUploadedFile(file, dst)
	retum := "/static/upload" + file.Filename
	c.JSON(http.StatusOK, gin.H{
		"code": 0,
		"msg":  "成功",
		"data": retum,
	})
}

/**
{
    "cmd": "online"
}

{
    "cmd":"send",
    "data":{
        "to_user_id": 2,
        "message":"hello 2"
    }
}
*/

var OnlineUser = make(map[int]*websocket.Conn)

type WSReq struct {
	Cmd  string      `json:"cmd"`
	Data interface{} `json:"data"`
}

type WSResp struct {
	Code int         `json:"code"`
	Msg  string      `json:"msg"`
	Data interface{} `json:"data"`
}

type SendS struct {
	ToUserId int    `json:"to_user_id"`
	Message  string `json:"message"`
}

type WSSendReq struct {
	Cmd  string `json:"cmd"`
	Data SendS  `json:"data"`
}

func Chat(c *gin.Context) {

	//get middle userId
	userId := c.GetUint("userId")

	// update websocket
	var upgrader = websocket.Upgrader{} // use default options

	conn, err := upgrader.Upgrade(c.Writer, c.Request, nil)
	if err != nil {
		log.Print("upgrade:", err)
		c.JSON(http.StatusOK, gin.H{
			"code": -1,
			"msg":  "websocket fail",
			"data": nil,
		})
		return
	}

	defer conn.Close()

	for {
		_, message, err := conn.ReadMessage()
		if err != nil {
			log.Println("read:", err)
			break
		}

		var req WSReq

		err = json.Unmarshal(message, &req)
		if err != nil {

			WSRespErr(conn, 1000, "illegal json")
			continue
		}

		switch req.Cmd {
		case "online":
			go Online(conn, message, int(userId))
		case "send":
			go Send(conn, message)
		default:
			WSRespErr(conn, 10001, "no function")
		}

	}
}

func Send(conn *websocket.Conn, message []byte) {

	var req WSSendReq
	err := json.Unmarshal(message, &req)
	if err != nil {
		WSRespErr(conn, 20001, "Parsing json failed ")
		return
	}

	if OnlineUser[req.Data.ToUserId] == nil {
		WSRespErr(conn, 20003, "not online")
		return
	}

	WSRespSuccess(OnlineUser[req.Data.ToUserId], req.Data.Message)

	WSRespSuccess(conn, "send ok")

}

func Online(conn *websocket.Conn, message []byte, userId int) {

	OnlineUser[userId] = conn
	WSRespSuccess(conn, userId)
}

func WSRespErr(conn *websocket.Conn, code int, msg string) {
	response := WSResp{
		Code: code,
		Msg:  msg,
		Data: nil,
	}

	responseStr, _ := json.Marshal(response)

	err := conn.WriteMessage(websocket.TextMessage, responseStr)
	if err != nil {
		log.Println("write:", err)
	}
}

func WSRespSuccess(conn *websocket.Conn, data interface{}) {
	response := WSResp{
		Code: 0,
		Msg:  "ok",
		Data: data,
	}

	responseStr, _ := json.Marshal(response)

	err := conn.WriteMessage(websocket.TextMessage, responseStr)
	if err != nil {
		log.Println("write:", err)
	}
}

func BookLike(c *gin.Context) {
	like := dao.FindReleaseByLike()
	c.JSON(http.StatusOK, gin.H{
		"code": 0,
		"msg":  "成功",
		"data": like,
	})
}

func AddBook(c *gin.Context) {
	var data request.AddBook
	err := c.ShouldBind(&data)
	if err != nil {
		c.JSON(http.StatusOK, gin.H{
			"code": 1000,
			"msg":  "发布失败",
			"data": nil,
		})
		return
	}
	user := c.GetUint("userID")
	u := dao.FindReleaseById(user)
	if user == 0 {
		c.JSON(http.StatusOK, gin.H{
			"code": 1000,
			"msg":  "用户未登录",
			"data": u,
		})
		return
	}
	add := dao.CreateRelease(data.Title, data.Types, data.Content, user)
	c.JSON(http.StatusOK, gin.H{
		"code": 0,
		"msg":  "成功",
		"data": add,
	})
}

func Follow(c *gin.Context) {
	list := dao.FindFollByType()
	c.JSON(http.StatusOK, gin.H{
		"code": 0,
		"msg":  "成功",
		"data": list,
	})
}

func ReleaseLike(c *gin.Context) {
	var data request.ReleaseLikes
	err := c.ShouldBind(&data)
	if err != nil {
		c.JSON(http.StatusOK, gin.H{
			"code": 1000,
			"msg":  err.Error(),
			"data": nil,
		})
		return
	}
	if data.Types == 1 {
		dao.CreateReleaseLike(data.TitleId)
	} else {
		dao.DeleteReleaseLike(data.TitleId)
	}
	c.JSON(http.StatusOK, gin.H{
		"code": 0,
		"msg":  "成功",
		"data": nil,
	})
}

func Comments(c *gin.Context) {
	var data request.CommentLike
	err := c.ShouldBind(&data)
	if err != nil {
		c.JSON(http.StatusOK, gin.H{
			"code": 1000,
			"msg":  err.Error(),
			"data": nil,
		})
		return
	}
	con := dao.CreateCommentLike(data.TitleId, data.Content, data.Likes)
	c.JSON(http.StatusOK, gin.H{
		"code": 0,
		"msg":  "成功",
		"data": con,
	})
}

func Reply(c *gin.Context) {
	var data request.Replya
	err := c.ShouldBind(&data)
	if err != nil {
		c.JSON(http.StatusOK, gin.H{
			"code": 1000,
			"msg":  err.Error(),
			"data": nil,
		})
		return
	}
	req := dao.CreateReplyComment(data.CommentId, data.Replys)
	if err != nil {
		c.JSON(http.StatusOK, gin.H{
			"code": 1000,
			"msg":  "回复评论失败",
			"data": nil,
		})
		return
	}
	c.JSON(http.StatusOK, gin.H{
		"code": 0,
		"msg":  "成功",
		"data": req,
	})
}

func ListLike(c *gin.Context) {
	list := dao.FindListLike()
	c.JSON(http.StatusOK, gin.H{
		"code": 0,
		"msg":  "回溯成功",
		"data": list,
	})
}

func VideoList(c *gin.Context) {
	list := dao.FindReleasesByLikeNumAndCommentNum()
	c.JSON(http.StatusOK, gin.H{
		"code": 0,
		"msg":  "查询成功",
		"data": list,
	})
}

func AddGroup(c *gin.Context) {
	var data request.Room
	err := c.ShouldBind(&data)
	if err != nil {
		c.JSON(http.StatusOK, gin.H{
			"code": 1000,
			"msg":  err.Error(),
			"data": nil,
		})
		return
	}
	room := dao.AddRoom(data.RoomId)
	if err != nil {
		c.JSON(http.StatusOK, gin.H{
			"code": 1000,
			"msg":  "创群失败",
			"data": nil,
		})
		return
	}
	c.JSON(http.StatusOK, gin.H{
		"code": 0,
		"msg":  "成功",
		"data": room,
	})
}

func DelMember(c *gin.Context) {
	var data request.RoomUser
	err := c.ShouldBind(&data)
	if err != nil {
		c.JSON(http.StatusOK, gin.H{
			"code": 1000,
			"msg":  err.Error(),
			"data": nil,
		})
		return
	}
	if data.Types == 1 {
		dao.CreateRoom(data.UserId)
	} else {
		dao.DeleteRoom(data.UserId)
	}
	c.JSON(http.StatusOK, gin.H{
		"code": 0,
		"msg":  "成功",
		"data": nil,
	})
}

func SetAdministrators(c *gin.Context) {
	var data request.Room
	err := c.ShouldBind(&data)
	if err != nil {
		c.JSON(http.StatusOK, gin.H{
			"code": 1000,
			"msg":  err.Error(),
			"data": nil,
		})
		return
	}
	del := dao.DelRoomId(data.RoomId)
	if err != nil {
		c.JSON(http.StatusOK, gin.H{
			"code": 1000,
			"msg":  "解散失败",
			"data": nil,
		})
		return
	}
	c.JSON(http.StatusOK, gin.H{
		"code": 1000,
		"msg":  "成功",
		"data": del,
	})
}

func SetJurisdiction(c *gin.Context) {
	var data request.Room
	err := c.ShouldBind(&data)
	if err != nil {
		c.JSON(http.StatusOK, gin.H{
			"code": 1000,
			"msg":  err.Error(),
			"data": nil,
		})
		return
	}
	del := dao.DelRoomId(data.RoomId)
	if err != nil {
		c.JSON(http.StatusOK, gin.H{
			"code": 1000,
			"msg":  "解散失败",
			"data": nil,
		})
		return
	}
	c.JSON(http.StatusOK, gin.H{
		"code": 1000,
		"msg":  "成功",
		"data": del,
	})
}

func DelGroup(c *gin.Context) {
	var data request.Room
	err := c.ShouldBind(&data)
	if err != nil {
		c.JSON(http.StatusOK, gin.H{
			"code": 1000,
			"msg":  err.Error(),
			"data": nil,
		})
		return
	}
	del := dao.DelRoomId(data.RoomId)
	if err != nil {
		c.JSON(http.StatusOK, gin.H{
			"code": 1000,
			"msg":  "解散失败",
			"data": nil,
		})
		return
	}
	c.JSON(http.StatusOK, gin.H{
		"code": 1000,
		"msg":  "成功",
		"data": del,
	})
}
